package com.sunchangming.stmdb;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 以固定间隔检测并打断死锁。 （TODO：现在还没实现打断）
 * 
 * @author cm
 * 
 */
public class DeadlockDetector implements Module, DeadlockDetectorMXBean {
	private final static Logger logger = LoggerFactory.getLogger(DeadlockDetector.class);

	private final Task task = new Task();
	private volatile MyThread thr;

	private static void lock2Keys(java.util.concurrent.CyclicBarrier cb, Object k1, Object k2) {
		final Lockey key = LockManager.get("test", k1);
		key.lock();
		try {
			cb.await(10, java.util.concurrent.TimeUnit.SECONDS);
			final Lockey key2 = LockManager.get("test", k2);
			key2.lock();
			key2.unlock();
		} catch (final Exception ex) {

		} finally {
			key.unlock();
		}
	}

	@Override
	public void testDeadLock() {
		doDeadLock();
	}

	public static void doDeadLock() {
		final java.util.concurrent.CyclicBarrier cb = new java.util.concurrent.CyclicBarrier(2);
		final Long key1 = 1L;
		final Long key2 = 2L;
		final Thread thr1 = new Thread(new Runnable() {

			@Override
			public void run() {
				lock2Keys(cb, key1, key2);
			}
		}, "testThread1");
		final Thread thr2 = new Thread(new Runnable() {

			@Override
			public void run() {
				lock2Keys(cb, key2, key1);
			}
		}, "testThread2");
		thr1.start();
		thr2.start();
		try {
			thr1.join();
			thr1.join();
		} catch (final Exception ex) {

		}
	}

	private static final class Task implements Runnable {
		private final ThreadMXBean tmx = ManagementFactory.getThreadMXBean();

		@Override
		public void run() {
			final long[] deadlockedThreadIds = tmx.findDeadlockedThreads();
			if (null == deadlockedThreadIds)
				return;
			final Map<Long, ThreadInfo> deadlockedThreads = new HashMap<Long, ThreadInfo>();

			for (final ThreadInfo tinfo : tmx.getThreadInfo(deadlockedThreadIds, tmx.isObjectMonitorUsageSupported(),
					tmx.isSynchronizerUsageSupported())) {
				try {
					if (null != tinfo && tinfo.getLockOwnerId() != -1)
						deadlockedThreads.put(tinfo.getThreadId(), tinfo);
				} catch (final Exception e) {
					logger.info("detect should retry");
				}
			}
			//logger.info(deadlockedThreads.values());
			//TODO:随机找一个打断
		}

	}

	@Override
	public synchronized void init() throws Exception {
		thr = new MyThread("deadlockDetector", task, 3000);
		thr.start();
		MyMbeanServer.getInstance().register(this);
	}

	@Override
	public synchronized void fini() {
		thr.shutdown();
	}

}
